package p2pmodule;

import java.util.ArrayList;
import java.util.List;

import dustconf.DustConf;
import dustlog.LogController;
import events.FileDownloadedListener;
import events.FileFoundListener;

/**
 * This class is a quick and ugly solution to have a p2p module where the Dust
 * components that needs p2p communication can go to gain it.
 * 
 * The idea is to rewrite the p2p component and merge this wrap into it by
 * giving it the proper interfaces and attributes. Right now p2p is more an API
 * than an independent component.
 * 
 * @author ole
 */
public class P2PModule {
	// Class constants.
	public final static int FILESERVER_PORT = 32000;
	public final static int GNUTELLA_SERVANT_PORT = 6346;
	
	// Class attributes.
	private static GnutellaServant gnutella;
	private static FileServer fileserver;
	
	/**
	 * Class constructor. Must be called before starting using this module.
	 * 
	 * @throws Exception:
	 * 		Raised if there were problems initializing the servant. If it
	 * 		occurs then the P2PModule cannot be used. 
	 */
	public P2PModule() throws Exception {
		fileserver = new FileServer(DustConf.getSharedFolder());
		fileserver.start();
		gnutella = new GnutellaServant(DustConf.getGnutellaPort(),
									   fileserver);
	}
	
	/**
	 * Method to tell the P2PModule to download the specified item. The handler
	 * specified will be executed when finished.
	 * 
	 * @param item:
	 * 		The item to download.
	 * @param callbacks:
	 * 		Listener to be executed when the download finish.
	 */
	public static void downloadItem(Item item,
									FileDownloadedListener callback) {
		List<FileDownloadedListener> callbacks = null;
		
		if (callback != null) {
			callbacks = new ArrayList<FileDownloadedListener>();
			callbacks.add(callback);
		}
		
		downloadItem(item, callbacks);
	}
	
	/**
	 * Method to tell the P2PModule to download the specified item. The list of
	 * handlers will be executed when the finished.
	 * 
	 * @param item:
	 * 		The item to download.
	 * @param callbacks:
	 * 		Listeners to be executed when the download finish.
	 */
	public static void downloadItem(Item item,
									List<FileDownloadedListener> callbacks) {
		// Checks module initialization.
		if (gnutella == null) {
			LogController.log("Cannot perform p2p downloads, P2PModule " +
			  				  "hasn't been initialized.");
			return;
		}
		
		/** TODO: Check if the item is already downloaded, in that case
		 * execute the handlers... the even needs to be build. **/
		
		// Perform the download.
		gnutella.download(item, callbacks);
	}
	
	/**
	 * Shutdown the enviroment. After calling this method, the module cannot be
	 * use again unless it is reinitialized.
	 */
	public static void shutdown() {
		// Stop the Gnutella servant.
		gnutella.shutdown();
		gnutella = null;
		
		// Stop the FileServer.
		fileserver.stopListening();
		fileserver = null;
	}
	
	/**
	 * This method perform a search inside the P2P network searching for the
	 * pattern passed in the file names, if it finds something it executes
	 * callback.
	 *   
	 * @param pattern:
	 * 		The pattern to search in the file names. 
	 * @param callbacks:
	 * 		Listener to be executed when something is found.
	 */
	public static void searchInName(String pattern,
									FileFoundListener callback) {
		List<FileFoundListener> callbacks = null;
		
		if (callback != null) {
			callbacks = new ArrayList<FileFoundListener>();
			callbacks.add(callback);
		}
		
		searchInName(pattern, callbacks);
	}
	
	/**
	 * This method perform a search inside the P2P network searching for the
	 * pattern passed in the file names, if it finds something it executes
	 * every handler in callbacks.
	 *   
	 * @param pattern:
	 * 		The pattern to search in the file names. 
	 * @param callbacks:
	 * 		Listeners to be executed when something is found.
	 */
	public static void searchInName(String pattern,
									List<FileFoundListener> callbacks) {
		// Checks module initialization.
		if (gnutella == null) {
			LogController.log("Cannot perform p2p searchs, P2PModule hasn't " +
							  "been initialized.");
			return;
		}
		
		// Perform the search.
		gnutella.search(pattern, callbacks);
	}
}
